#include <cute_base.h>
#include <cute_runner.h>
#include <cute_suite.h>
#include <cute_test.h>
#include <cute_to_string.h>
#include <cute_xml_file.h>
#include <ide_listener.h>
#include <xml_listener.h>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include "raphTools/Random.h"
#include "raphTools/Tools.h"
#include "raphTools/WorkspaceTools.h"

using namespace raph;
using namespace raph::tools;
using namespace raph::type;

T_FLOAT64 mean(std::vector<T_INT32> &v);
T_FLOAT64 sd(std::vector<T_INT32> &v);
void runAllTests(int argc, char const *argv[]);
void testIsEqual();
void testIsPrime();

void testIsEqual()
    {
        {
        T_FLOAT128 a = 155.65;
        T_FLOAT128 b = 155.75;
        T_FLOAT128 p = 1.0;
        bool res = Numbers::isEqual(a, b, p);
        bool resTheo
            {
            true
            };
        ASSERT(res == resTheo);
        }

        {
        T_FLOAT128 a = 155.65;
        T_FLOAT128 b = 155.75;
        T_FLOAT128 p = 0.1;
        bool res = Numbers::isEqual(a, b, p);
        bool resTheo
            {
            true
            };
        ASSERT(res == resTheo);
        }

        {
        T_FLOAT128 a = 145758.12345;
        T_FLOAT128 b = 145758.12344;
        T_FLOAT128 p = 1e-8;
        bool res = Numbers::isEqual(a, b, p);
        bool resTheo
            {
            true
            };
        ASSERT(res == resTheo);
        }

        {
        T_FLOAT128 a = 145758.12345;
        T_FLOAT128 b = 145758.12344;
        T_FLOAT128 p = 1e-9;
        bool res = Numbers::isEqual(a, b, p);
        bool resTheo
            {
            false
            };
        ASSERT(res == resTheo);
        }

        {
        T_FLOAT128 a = 0.001;
        T_FLOAT128 b = -0.001;
        T_FLOAT128 p = 0.1;
        bool res = Numbers::isEqual(a, b, p);
        bool resTheo
            {
            false
            };
        ASSERT(res == resTheo);
        }

        {
        T_FLOAT128 a = -55.1;
        T_FLOAT128 b = 55.1;
        T_FLOAT128 p = 0.1;
        bool res = Numbers::isEqual(a, b, p);
        bool resTheo
            {
            false
            };
        ASSERT(res == resTheo);
        }

        {
        T_FLOAT128 a = -55.1;
        T_FLOAT128 b = 55.2;
        T_FLOAT128 p = 0.1;
        bool res = Numbers::isEqual(a, b, p);
        bool resTheo
            {
            false
            };
        ASSERT(res == resTheo);
        }
    }

void testIsPrime()
    {
        {
        bool b = Numbers::isPrime(0);
        ASSERT(b == false);
        }
        {
        bool b = Numbers::isPrime(1);
        ASSERT(b == false);
        }
        {
        bool b = Numbers::isPrime(2);
        ASSERT(b == true);
        }
        {
        bool b = Numbers::isPrime(3);
        ASSERT(b == true);
        }
        {
        bool b = Numbers::isPrime(4);
        ASSERT(b == false);
        }
        {
        bool b = Numbers::isPrime(17);
        ASSERT(b == true);
        }
        {
        bool b = Numbers::isPrime(21);
        ASSERT(b == false);
        }
    }

void runAllTests(int argc, char const *argv[])
    {
    cute::suite s {};
    s.push_back(CUTE(testIsEqual));
    s.push_back(CUTE(testIsPrime));
    cute::xml_file_opener xmlfile(argc, argv);
    cute::xml_listener<cute::ide_listener<> > lis(xmlfile.out);
    cute::makeRunner(lis, argc, argv)(s, "All tests for tools library");
    }

int main(int argc, char const *argv[])
    {
    runAllTests(argc, argv);
    return 0;
    }

T_FLOAT64 mean(std::vector<T_INT32> &v)
    {
    T_UINT32 total = 0;
    for (T_INT32 &n : v)
        {
        total += n;
        }

    return static_cast<T_FLOAT64>(total / v.size());
    }

T_FLOAT64 sd(std::vector<T_INT32> &v)
    {
    T_FLOAT64 m = mean(v);
    T_FLOAT64 sum = 0.0;
    for (T_INT32 &n : v)
        {
        T_FLOAT64 delta = static_cast<T_FLOAT64>(n) - m;
        sum += delta * delta;
        }

    return static_cast<T_FLOAT64>(sqrt(sum / (static_cast<T_FLOAT64>(v.size()) - 1)));
    }
